﻿namespace Record类型
{
    internal class Program
    {
        static void Main(string[] args)
        {
            //普通Class类型比较
            //三种比较方式：==、Equals()、ReferenceEquals()，默认均比较引用地址。
            Student s1 = new Student() { Id = 1, Name = "张三" };
            Student s2 = new Student() { Id = 1, Name = "张三" };
            Student s3 = s1;
            Person p1 = s1;

            Console.WriteLine(s1);  //默认调用ToString()方法，输出命名空间+类名
            Console.WriteLine(s1 == s2); // False，引用类型，比较引用地址
            Console.WriteLine(s1 == s3); // True，引用类型，比较引用地址
            Console.WriteLine(p1 == s1);    // True，引用类型，比较引用地址
            Console.WriteLine(s1.Equals(s2));   // False，引用类型，比较引用地址
            Console.WriteLine(s1.Equals(s3));   // True，引用类型，比较引用地址
            Console.WriteLine(object.ReferenceEquals(s1, s2));   //False
            Console.WriteLine(object.ReferenceEquals(s1, s3));   //True
            Console.WriteLine(object.ReferenceEquals(s1, p1));   //True


            //record(记录)类型比较
            Teacher t1 = new Teacher(1, "李四", 10);
            Teacher t2 = new Teacher(1, "李四", 10);
            Teacher t3 = new Teacher(1, "李四", 30);

            Console.WriteLine(t1);  //默认调用ToString()方法，输出属性名和值
            Console.WriteLine(t1 == t2); // True，记录类型，比较属性值
            Console.WriteLine(t1.Equals(t2));   // True，记录类型，比较属性值
            Console.WriteLine(object.ReferenceEquals(t1, t2));   //False
            Console.WriteLine(t1 == t3);    // False，记录类型，比较属性值

            //t1.Age = 20; //记录类型的属性默认是不可变的，尝试修改会报错
            Teacher2 t21 = new Teacher2(1, "王五") { Age = 25 };
            t21.Age = 30; //可以修改，因为Age属性是可变的
            Console.WriteLine(t21); //输出：Teacher2 { Id = 1, Name = 王五, Age = 30 }

            Teacher2 t22 = new Teacher2(1, "王五");
            Console.WriteLine(t22); //输出：Teacher2 { Id = 1, Name = 王五, Age = 0 }

            //使用==比较
            Console.WriteLine(t21 == t22); // False，因为Age属性不同。会把Age属性也纳入比较范围

            //使用with表达式创建对象的副本
            Teacher2 t23 = t21 with { }; //创建t21的副本，属性值相同
            Console.WriteLine(t23); //输出：Teacher2 { Id = 1, Name = 王五, Age = 30 }
            Console.WriteLine(t21 == t23);  // True，属性值相同
            Console.WriteLine(ReferenceEquals(t21, t23));    // False，引用地址不同

            //使用with表达式修改部分属性值创建新对象
            Teacher2 t24 = t21 with { Age = 35 }; //创建t21的副本，但修改Age属性
            Teacher2 t25 = t21 with { Id = 20 };    //创建t21的副本，但修改Id属性
            Console.WriteLine(t24);
            Console.WriteLine(t25);


            Cat c1 = new Cat(1, "mimi", "咪咪");
            Cat c2 = new Cat(2, "miaomiao");
            Console.WriteLine(c2);
        }
    }

    class Student : Person
    {
        public int Id { get; set; }
        public string? Name { get; set; }
    }

    class Person
    {
        public int Age { get; set; }
    }

    //申明一个记录类型
    record Teacher(int Id, string Name, int Age);

    //记录类型也可以包含可变属性,但主构造函数中的属性默认是不可变的
    //Teacher2 中的Id和Name是不可变的，Age是可变的
    record Teacher2(int Id, string Name)
    {
        public int Age { get; set; }
    }

    record Cat(int Id, string Name)
    {
        public string NickName { get; set; }

        //声明额外的构造函数，而且必须使用this关键字调用主构造函数
        public Cat(int id, string name, string nickName) : this(id, name)
        {
            NickName = nickName;
        }
    }
}
